package com.zf.generic;

import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.List;
import java.util.StringJoiner;

/**
 * 通过反射
 * 获取 《类自身、父类、父接口、属性，方法参数、方法返回》 定义的泛型类型中的泛型参数信息。
 * 1、“类自身" 的泛型参数，被擦除为 限定类型
 * 2、“父类、父接口、属性，方法参数、方法返回” 中的泛型，如果制定了明确的类型，则被保留，否则也被擦除为限定类型
 */
 public class ReflectGenericParameterTest {

    static class Foo<E extends CharSequence, T> {
        public List<Bar> children = new ArrayList<Bar>();
 
        public List<StringBuilder> foo(List<String> foo, String a) {
            return null;
        }

        public List<StringJoiner> testRet(){
            return null;
        }
 
        public  void bar(List<? extends String> param) {
        }
    }

    static class Bar extends Foo<String, Integer> {
    }

    interface InterFoo<T>{

    }
    interface InterFoo2<T>{

    }

    static class Bar2 implements InterFoo<List<String>>, InterFoo2<String>{

    }
 
    public static void main(String[] args) throws Exception {

        System.out.println("父类的泛型参数类型信息====================");
        getSuperClassGeneric();

        System.out.println("\n父接口的泛型参数类型信息====================");
        getSuperInterfaceGeneric();

        System.out.println("\n类自身声明的泛型参数类型信息====================");
        getClassSelfGeneric();

        System.out.println("\n获取类中属性的泛型参数类型信息====================");
        getFieldGeneric();

        System.out.println("\n方法返回值的泛型参数类型信息====================");
        getMethodReturnValueGeneric();

        System.out.println("\n获取方法参数的泛型参数类型信息====================");
        getMethodParameterGeneric();

    }

    /**
     * 所继承的父类的泛型参数类型信息
     */
    public static void getSuperClassGeneric() {
        // 获取类继承的泛型父类，父类不是泛型类型也会被返回，所以要判断
        Type genericSuperclass = Bar.class.getGenericSuperclass();
        // 判断父类是否为泛型
        if (genericSuperclass instanceof ParameterizedType){
            ParameterizedType type = (ParameterizedType) genericSuperclass;
            // 获取父类的原始类型，不包含泛型参数
            Type rawType = type.getRawType();
            System.out.printf("父类：%s, 包含的泛型参数：\n", rawType);
            // 获取 继承父类时 填写的父类的 泛型参数类型 列表
            Type[] arguments = type.getActualTypeArguments();
            for (Type argument : arguments) {

                // 如果泛型参数也是个泛型
                if (argument instanceof ParameterizedType){
                    // System.out.println(((ParameterizedType) argument).getRawType());
                    System.out.println(argument.toString());
                    continue;
                }

                // 如果泛型参数不是泛型，则返回Class
                Class argument1 = (Class) argument;
                System.out.println(argument1);
            }
        }
    }
    /**
     * 所实现的父接口的泛型参数类型信息
     */
    public static void getSuperInterfaceGeneric() {
        // 获取类实现的泛型接口，可能有多个，如果不是泛型类型也会被返回，所以要做判断
        Type[] interTypes = Bar2.class.getGenericInterfaces();
        for (Type interType : interTypes) {
            // 判断接口是不是泛型
            if (interType instanceof ParameterizedType){
                ParameterizedType pt = (ParameterizedType) interType;
                // 获取父接口的原始类型，不包含泛型参数
                Type rawType = pt.getRawType();
                System.out.printf("父接口：%s, 包含的泛型参数：\n", rawType);
                // 获取 实现接口填写的父接口的泛型参数类型列表
                Type[] iargs = pt.getActualTypeArguments();
                for (Type iarg : iargs) {

                    // 如果泛型参数也是个泛型
                    if (iarg instanceof ParameterizedType){
                        // System.out.println(((ParameterizedType) iarg).getRawType());
                        System.out.println(iarg.toString());
                        continue;
                    }

                    // 如果泛型参数不是泛型，则返回Class
                    Class aclass = (Class) iarg;
                    System.out.println(aclass);
                }
            }
        }
    }
    /**
     * 类自身声明的泛型参数类型信息
     */
    public static void getClassSelfGeneric() {
        // 获取 类自身声明的泛型参数列表，如果类自身不是泛型，则返回空数组
        // 一般类自身的泛型参数都是一个标识符如 T、E 等，这些泛型参数的类型是 Object, 如果是存在限定类型，则泛型参数类型是限定类型
        System.out.printf("类自身：%s，包含的泛型参数：\n", Foo.class);
        TypeVariable<Class<Foo>>[] typeVariables = Foo.class.getTypeParameters();
        for (TypeVariable<Class<Foo>> typeVariable : typeVariables) {
            Type type = typeVariable.getBounds()[0];
            Class aClass = (Class) type;
            System.out.println(aClass);
        }
    }

    /**
     * 获取类中属性的泛型参数类型信息
     */
    public static void getFieldGeneric() throws NoSuchFieldException {
        // 获取Foo类中名为"children"的字段
        Field oneField = Foo.class.getField("children");
        // 获取该字段的泛型类型信息，如果不是泛型类型也会被返回，所以要做判断
        Type genericType = oneField.getGenericType();
        // 判断属性的类型是否为泛型
        if (genericType instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) genericType;
            // 泛型的原始类型，不包含泛型参数
            Type rawType = parameterizedType.getRawType();
            System.out.printf("属性：%s, 泛型的原始类型：%s, 包含的泛型参数：\n", oneField.getName(), rawType);
            // 获取泛型类型中的泛型参数类型列表
            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments) {
                Class fieldArgClass = (Class) actualTypeArgument;
                System.out.println(fieldArgClass);
            }
        }
    }
    /**
     * 获取方法返回值的泛型参数类型信息
     */
    public static void getMethodReturnValueGeneric() throws NoSuchMethodException {
        Method testRetMethod = Foo.class.getMethod("testRet");
        // 获取方法返回的泛型类型，如果不是泛型类型也会被返回，所以要做判断
        Type genericReturnType = testRetMethod.getGenericReturnType();
        // 判断返回类型是否为泛型
        if (genericReturnType instanceof ParameterizedType) {
            ParameterizedType type = (ParameterizedType) genericReturnType;
            System.out.printf("方法：%s 返回值的 泛型的原始类型：%s, 包含的泛型参数：\n", testRetMethod.getName(), type.getRawType());
            // 获取泛型类型的泛型参数类型列表
            Type[] actualTypeArguments = type.getActualTypeArguments();
            // 遍历每一个泛型参数类型
            for (Type actualTypeArgument : actualTypeArguments) {
                Class typeArgClass = (Class) actualTypeArgument;
                System.out.println(typeArgClass);
            }
        }
    }

    /**
     * 获取方法参数的泛型参数类型信息
     */
    public static void getMethodParameterGeneric() throws NoSuchMethodException {
        Method fooMethod = Foo.class.getMethod("foo", List.class, String.class);
        // 获取该方法的所有的参数类型信息（带有泛型）
        Type[] genericParameterTypes = fooMethod.getGenericParameterTypes();
        // 判断参数类型是否为泛型
        for (Type genericParameterType : genericParameterTypes) {
            if (genericParameterType instanceof ParameterizedType){
                ParameterizedType parameterizedType = (ParameterizedType) genericParameterType;
                System.out.printf("方法：%s 的 泛型的原始类型：%s, 包含的泛型参数：\n", fooMethod.getName(), parameterizedType.getRawType());
                // 获取泛型类型中的 泛型参数类型列表
                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                for (Type actualTypeArgument : actualTypeArguments) {
                    Class realType = (Class) actualTypeArgument;
                    System.out.println(realType);
                }
            }
        }
    }
}
